﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Civilisation_code.PCarte;
using Civilisation_code.PJoueur;
using System.ComponentModel;
using Civilisation_code.PInterfaces_Fabrique_Unite;

namespace Civilisation_code.PJoueur
{
    /// <summary>
    /// Classe abstraite Unite contenant les caractéristiques d'une unité et ses actions possibles
    /// </summary>
    [Serializable]
    public abstract class Unite : INotifyPropertyChanged
    {

        [field : NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            if(PropertyChanged!=null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        /// <summary>
        /// Case où est située l'unité
        /// </summary>
        protected Case _case;
        public Case Case {
            get
            {
                return _case;
            }
            set
            {
                _case = value;
                OnPropertyChanged("unite_bouge");

            }
        }

        /// <summary>
        /// Joueur possédant l'unité
        /// </summary>
        public Joueur _joueur { get; set; }

        /// <summary>
        /// Attaque de base de l'unité
        /// </summary>
        public int _attaque_base { get; set; }

        /// <summary>
        /// Défense de base de l'unité
        /// </summary>
        public int _defense_base { get; set; }

        /// <summary>
        /// Mouvement restant de l'unité
        /// </summary>
        public int _mvt_restant { get; set; }

        /// <summary>
        /// Mouvement de base de l'unité
        /// </summary>
        public int _mvt_base { get; set; }

        /// <summary>
        /// Vie restante de l'unité
        /// </summary>
        public int _vie_restante { get; set; }

        /// <summary>
        /// Vie de base de l'unité
        /// </summary>
        public int _vie_base { get; set; }

        /// <summary>
        /// Dit si l'unité a bougé le tour courant
        /// </summary>
        protected bool _actif = false;

        /// <summary>
        /// Constructeur
        /// </summary>
        /// <param name="aBase">Attaque de base de l'unité</param>
        /// <param name="dBase">Défense de base de l'unité</param>
        /// <param name="mBase">Mouvement de base de l'unité</param>
        /// <param name="vMax">Vie de base de l'ubité</param>
        /// <param name="c">Case où est située l'unité</param>
        /// <param name="j">Joueur possédant l'unité</param>
        public Unite(int aBase, int dBase, int mBase, int vMax, Case c, Joueur j)
        {
            //Initialisation des attributs
            _attaque_base = aBase;
            _defense_base = dBase;
            _mvt_base = mBase;
            _mvt_restant = _mvt_base;
            _vie_base = vMax;
            _vie_restante = _vie_base;
            _joueur = j;
            _case = c;
            j._unites.Add(this);
            c.ajoutUnite(this);

        }

        /// <summary>
        /// Calcul des points d'attaque de l'unité
        /// </summary>
        /// <returns>Les points d'attaque de l'unité</returns>
        public int calculerPointAttaque()
        {
            return _vie_restante * _attaque_base / _vie_base;
        }

        /// <summary>
        /// Calcul des points de défense de l'unité
        /// </summary>
        /// <returns>Les points de défense de l'unité</returns>
        public int calculerPointDefense()
        {
            return _vie_restante * _defense_base / _vie_base;
        }

        /// <summary>
        /// Déplacer l'unité vers une case envoyée en paramètre
        /// </summary>
        /// <param name="c">Case destination</param>
        /// <returns>Renvoie vrai si le déplacement a pu s'effectuer
        ///          Renvoie faux sinon</returns>
        virtual public bool deplacer(Case c)
        {
            //Case nulle : erreur
            if (c == null)
                return false;
            //Case ennemie : erreur
            if (c.Unites.Count > 0 && c.Unites[0]._joueur != _joueur)
                return false;
            if (c.Ville != null && c.Ville.Joueur != _joueur)
                return false;

            int distance = _case.calculerDistance(c);
            if (_mvt_restant >= distance)
            {
                _actif = true;
                _mvt_restant -= distance;
                _case.retirerUnite(this);
                _case = c;
                c.Unites.Add(this);
                Case = c;
                _joueur.vueSur();
                return true;
            }
            return false;
        }

        /// <summary>
        /// Liste des cases que l'unité a une vue dessus
        /// </summary>
        /// <returns>Liste des cases où l'unité a une vue dessus</returns>
        public List<Case> vueSur()
        {
            return _case.vueSur(2);
        }

        /// <summary>
        /// Redonne des points de mouvement à chaque tour
        /// </summary>
        public void nouveauTour()
        {
            if (_actif == false && _vie_restante<_vie_base)
            {
                _vie_restante += 1;
            }
           _actif = false;    
            _mvt_restant = _mvt_base;
        }

        /// <summary>
        /// Traitement lorsque l'unité passe son tour
        /// </summary>
        public void passerTour()
        {
            _mvt_restant = 0;
        }
		
        /// <summary>
        /// Tuer l'unité
        /// </summary>
		public void tuer()
		{
		//Retire tous les liens
		
		//case => unite
            _case.Unites.Remove(this);
		
		//joueur => unites
		_joueur._unites.Remove(this);

        OnPropertyChanged("unite_morte");

		//unite=> case et unite=>joueur seront détruits à la destruction de l'unité
		_case = null;
		_joueur = null;
		}
        
        /// <summary>
        /// Donne le type de l'unité
        /// </summary>
        /// <returns>le type</returns>
        public string getType()
        {
            if (this.GetType().IsSubclassOf(typeof(Directeur)))
                return "Directeur";
            //Si l'unité est un enseignant
            else if (this.GetType().IsSubclassOf((typeof(Enseignant))))
                return "Enseignant";
            //Sinon il est étudiant
            else
                return  "Etudiant";
        }
    }
}
